#include <iostream>

using std::cout;
using std::endl;

/*
    动态多态的5个充要条件：
    1、基类要定义虚函数
    2、派生类要重写该虚函数。   不然都指向了Base::print，都打印的_base=10\111
    3、创建派生类对象。         没对象第4步怎么指，怎么创建派生对象的虚表？
    4、基类指针（引用）指向派生类对象。   通常发生在传参处
    5、基类指针\引用调用该虚函数。 
        注意是派生类中重写的那个，你调用Base::print()一样不是多态。   警车鸣笛

    哪些不能设置为虚函数：
    1、普通函数 非成员函数
    2、静态成员函数。没有this指针、被共享不能体现多态、体现在编译时而非运行时
    虚函数用于实现多态性，它允许在运行时动态地选择调用哪个函数，通过对象的虚表来实现。
    然而，静态函数是与类本身相关联的，而不是与类的实例相关联的，因此它们不会被用于多态性的实现。
    3、内联函数，因为体现在编译时。virtual+inline会自动去掉inline
    4、友元函数如果是普通函数则不行，成员函数则可以
    5、构造函数，体现在编译时、不能被继承、构造函数如果是虚函数，
      就需要虚函数指针进行调用，然而此时还没有对象

    能不能被继承，不是判断能不能设为虚函数的标准。
    比如友元、析构函数就不能被继承、但可以设为虚函数

    什么是体现在编译时：
    比如创建一个对象，那在编译时就已经知道了会在这里调用哪个构造函数，没有多态性
    而如果是运行时，则会根据创建对象的不同，传入参数的不同，产生不同结果，动态多态

    虚函数和动态多态的关系：
    虚函数是为了实现动态多态而生的，有虚函数不一定能实现动态多态
*/

class Base;

class Line{
public:
    virtual
    void setBase(Base &base, long x);
};

class Base{
    friend void Line::setBase(Base &base,long x);
public:
    virtual
    void print(){
        cout<<Base::_base<<endl;
    }
    Base(long base=0)
    : _base(base)
    {
        cout<<"Base()"<<endl;
    }
    ~Base(){
        cout<<"~Base()"<<endl;
    }

private:
    long _base;
};

void Line::setBase(Base &base, long x){
    base._base=x;
}

class Deriver
: public Base
{
public:
    void print(){
        // 返回类型、函数名字、参数列表一样。
        // 函数体可以不一样
        // 参数列表里的参数名字可以不一样
        // 参数列表里的默认值可以不一样，比如一个int x=0，一个=1，但是都要写出来

        // 比如这里就不能写成int print，
        // 因为继承了void print，相当于有两个同名函数print，仅靠返回类型不能区分他俩
        cout<<_deriver<<endl;
    }

    Deriver(long base=0,long deriver=0)
    : Base(base)
    , _deriver(deriver)
    {
        cout<<"Deriver()"<<endl;
    }
    ~Deriver(){
        cout<<"~Deriver()"<<endl;
    }
private:
    long _deriver;
};

void func(Base *pbase){
    pbase->print();     
    //func函数的参数pbase是一个Base类的指针，
    //但是当你调用func(&deriver)时，实际上传入的是一个Deriver类的对象地址，
    //在func函数内部，通过pbase指针调用print函数时，
    //会根据对象的实际类型（即Deriver）来确定调用的函数，这就是多态的表现。
}

void test(){
    cout<<sizeof(Base)<<endl;
    cout<<sizeof(Deriver)<<endl;
    // 16 24
    // 只要有虚函数，对象里就会多一个虚函数指针，指向虚函数表，再从虚表中找到函数
    // 如果该类有派生类，那么派生类也有虚函数，它的对象也有虚函数指针指向派生类的虚表

    cout<<endl;
    Base base(10);
    base.print();

    cout<<endl;
    Deriver deriver(111,222);
    deriver.Base::print();
    deriver.print();

    cout<<endl;
    func(&base);    //10
    func(&deriver); //222，如果base里的print去掉virtual，则111
}

int main()
{   
    test();
    return 0;
}

